module;
#include <cstddef> // for nullptr_t
#include <type_traits> // for true_type, false_type, and bool_constant<>
#include <iostream>

export module Code_19_8_1;

//[1]
// primary template: in general T is not a fundamental type
template<typename T>
struct IsFundaT : std::false_type {};
//[1]
// macro to specialize for fundamental types
#define MK_FUNDA_TYPE(T) \
template<> struct IsFundaT<T> : std::true_type { }; \

//[1]
MK_FUNDA_TYPE(void)
MK_FUNDA_TYPE(bool)
MK_FUNDA_TYPE(char)
MK_FUNDA_TYPE(signed char)
MK_FUNDA_TYPE(unsigned char)
MK_FUNDA_TYPE(wchar_t)
MK_FUNDA_TYPE(char16_t)
MK_FUNDA_TYPE(char32_t)
MK_FUNDA_TYPE(signed short)
MK_FUNDA_TYPE(unsigned short)
MK_FUNDA_TYPE(signed int)
MK_FUNDA_TYPE(unsigned int)
MK_FUNDA_TYPE(signed long)
MK_FUNDA_TYPE(unsigned long)
MK_FUNDA_TYPE(signed long long)
MK_FUNDA_TYPE(unsigned long long)
MK_FUNDA_TYPE(float)
MK_FUNDA_TYPE(double)
MK_FUNDA_TYPE(long double)
MK_FUNDA_TYPE(std::nullptr_t)

//[1]
template<typename T>
void test(T const&)
{
    if (IsFundaT<T>::value) {
        std::cout << "T is a fundamental type" << '\n';
    }
    else {
        std::cout << "T is not a fundamental type" << '\n';
    }
}

export
namespace Code_19_8_1 {

    void run()
    {         
        //[1]
        test(7);
        test("hello");
    }
}